package com.seed.application.service.remove;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.seed.core.action.RemoveAction;
import com.seed.core.enumeration.Cascade;
import com.seed.core.pojo.Const;
import com.seed.core.pojo.seed.*;
import com.seed.util.*;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class RemoveService {

    private final Seed seed;
    private final RemoveAction action;

    public RemoveService(Seed seed, RemoveAction action) {
        this.seed = seed;
        this.action = action;
    }

    public boolean exec(Serializable id) {
        remove(seed, id);
        return true;
    }

    public boolean execBatch(List<Serializable> ids) {
        removeBatch(seed, ids);
        return true;
    }



    /**
     * 删除单条数据
     * @param seed 元数据
     * @param id 主键对应的值
     */
    public static void remove(Seed seed, Serializable id) {
        String tableName = seed.getTableName();
        Row row = Db.selectOneById(tableName, Const.ID, id);
        if(row == null) throw new RuntimeException("数据不存在");

        Map<String, Relation> relations = SeedKit.getRelations(seed);
        if(relations != null) {
            for(Map.Entry<String, Relation> entry: relations.entrySet()) {
                Relation relation = entry.getValue();
                if(relation instanceof Habtms habtm) {
                    removeHabtm(habtm, row);
                } else if(relation instanceof HasManys hasMany) {
                    removeHasMany(hasMany, row);
                } else if(relation instanceof HasOnes hasOne) {
                    removeHasOne(hasOne, row);
                }  // BelongsTo不能删
            }
        }

        if(Db.deleteById(tableName, Const.ID, id) != 1) throw new RuntimeException("删除失败");
    }

    public static void removeBatch(Seed seed, List<Serializable> ids) {
        for(Serializable id: ids) remove(seed, id);
    }

    /**
     * 删除hasOne关系的数据
     * @param hasOne 关系
     * @param self 主数据
     */
    private static void removeHasOne(HasOnes hasOne, Row self) {
        Cascade cascade = hasOne.getCascade();
        if(Cascade.none == cascade) return;

        if(cascade == null) cascade = Cascade.check; // 默认check
        Seed selfSeed = hasOne.selfSeed();
        Seed targetSeed = hasOne.targetSeed();
        String tableName = targetSeed.getTableName();
        String targetColumn = hasOne.targetColumn();
        QueryCondition queryCondition = HasOneKit.getQueryCondition(hasOne, self);

        if(cascade.equals(Cascade.setnull)) {
            boolean result = DbChain.table(tableName).set(targetColumn, null).where(queryCondition).update();
            if(result) return;
            throw new RuntimeException("删除失败");
        }

        Row row = DbChain.table(tableName).where(queryCondition).one();
        if(row == null) return;

        if(cascade.equals(Cascade.check)) {
            throw new RuntimeException(String.format("【%s】关联数据【%s】【%s】还存在，不能删除", selfSeed.getLabel(), targetSeed.getLabel(), row.get("id")));
        }

        Map<String, Relation> relations = SeedKit.getRelations(targetSeed);
        for(Map.Entry<String, Relation> entry: relations.entrySet()) {
            Relation relation = entry.getValue();
            if(relation instanceof Habtms habtm) {
                removeHabtm(habtm, row);
            } else if(relation instanceof HasManys hasMany1) {
                removeHasMany(hasMany1, row);
            } else if(relation instanceof HasOnes hasOne1) {
                removeHasOne(hasOne1, row);
            }  // BelongsTo不用管
        }

        if(!DbChain.table(tableName).where(queryCondition).remove()) throw new RuntimeException("删除失败");
    }

    /**
     * 删除hasMany关系的数据
     * @param hasMany 关系
     * @param self 主数据
     */
    private static void removeHasMany(HasManys hasMany, Row self) {
        Cascade cascade = hasMany.getCascade();
        if(Cascade.none == cascade) return;

        if(cascade == null) cascade = Cascade.check;
        Seed selfSeed = hasMany.selfSeed();
        Seed targetSeed = hasMany.targetSeed();
        String tableName = targetSeed.getTableName();
        String targetColumn = hasMany.targetColumn();
        QueryCondition queryCondition = HasManyKit.getQueryCondition(hasMany, self);
        if(cascade.equals(Cascade.setnull)) {
            if(StrUtil.isNotBlank(targetColumn)) {
                if(DbChain.table(tableName).set(targetColumn, null).where(queryCondition).update()) return;
            }

            throw new RuntimeException("删除失败");
        }

        List<Row> rows = DbChain.table(tableName).where(queryCondition).list();
        if(rows.isEmpty()) return;

        String label = StrUtil.isBlank(selfSeed.getLabel()) ? selfSeed.getName() : selfSeed.getLabel();
        if(cascade.equals(Cascade.check)) {
            throw new RuntimeException(String.format("【%s】关联数据【%s】还有【%s】条存在，不能删除", label, hasMany.getLabel(), rows.size()));
        }

        Map<String, Relation> relations = SeedKit.getRelations(targetSeed);
        for(Map.Entry<String, Relation> entry: relations.entrySet()) {
            Relation relation = entry.getValue();

            if(relation instanceof Habtms habtm) {
                for(Row row: rows) removeHabtm(habtm, row);
            } else if(relation instanceof HasManys hasMany1) {
                for(Row row: rows) removeHasMany(hasMany1, row);
            } else if(relation instanceof HasOnes hasOne1) {
                for(Row row: rows) removeHasOne(hasOne1, row);
            }  // BelongsTo不用管
        }

        if(!DbChain.table(tableName).where(queryCondition).remove()) {
            throw new RuntimeException("删除失败");
        }
    }

    /**
     * 删除habtm关系的数据
     * @param habtm 关系
     * @param self 主数据
     */
    private static void removeHabtm(Habtms habtm, Row self) {
        Cascade cascade = habtm.getCascade();
        if(Cascade.none == cascade) return;

        if(cascade == null) cascade = Cascade.check;
        Seed selfSeed = habtm.selfSeed();
        Seed targetSeed = habtm.targetSeed();
        String through = habtm.throughTableName();
        QueryCondition queryCondition = HabtmKit.getThroughQueryCondition(habtm, self);
        List<Row> rows = DbChain.table(through).where(queryCondition).list();
        if(rows.isEmpty()) return;

        if(cascade.equals(Cascade.check)) {
            throw new RuntimeException(String.format("【%s】关联数据【%s】还有【%s】条还存在，不能删除", selfSeed.getLabel(), targetSeed.getLabel(), rows.size()));
        }

        if(cascade.equals(Cascade.setnull) || cascade.equals(Cascade.force)) {
            if(DbChain.table(through).where(queryCondition).remove()) return;
            throw new RuntimeException("删除失败");
        }
    }
}
